package com.huanzhidadi.ratelimiter.aspect;

import com.alibaba.fastjson2.JSON;
import com.huanzhidadi.ratelimiter.limiter.LeakyBucketRateLimiter;
import com.huanzhidadi.ratelimiter.limiter.TokenBucketRateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

@Aspect
@Component
@Slf4j
public class ControllerLimitAspect {

    /**
     * 漏桶算法
     */
    /*@Autowired
    private LeakyBucketRateLimiter rateLimiter;*/

    /**
     * 令牌桶限流法
     */
    @Autowired
    private TokenBucketRateLimiter rateLimiter;

    @Pointcut("execution(public * com.huanzhidadi.*.controller..*.*(..))")
    public void controllerLimit(){

    }

    @Around("controllerLimit()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (null == attributes) {
            return joinPoint.proceed();
        }
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        log.debug("URL : " + request.getRequestURL().toString());
        log.debug("HTTP_METHOD : " + request.getMethod());
        log.debug("IP : " + request.getRemoteAddr());
        Enumeration<String> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String name = enu.nextElement();
            log.debug("name:{},value:{}", name, request.getParameter(name));
        }
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //请求的 类名、方法名
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = signature.getName();
        Object[] args = joinPoint.getArgs();
        try {
            log.debug("{}方法{}()请求参数：{}", className, methodName, JSON.toJSONString(args));
        } catch (Exception e) {
            log.debug("{}方法{}()请求参数：{}", className, methodName, args.toString());
        }
        // 漏桶算法
        boolean flag = rateLimiter.tryAcquire();
        if (flag) {
            log.info("--------流量被放行--------");
            return joinPoint.proceed();
        } else {
            log.info("流量被限制");
            return "流量被限制";
        }
    }

}
